package com.demo.webapp.kcfinder;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.demo.common.ClassLoaderUtils;
import com.demo.webapp.kcfinder.config.ActionConfig;
import com.demo.webapp.kcfinder.config.Configuration;
import com.demo.webapp.kcfinder.config.ConfigurationException;
import com.demo.webapp.kcfinder.config.ConfigurationManager;
import com.demo.webapp.kcfinder.config.PackageConfig;
import com.demo.webapp.kcfinder.context.ActionContext;
import com.demo.webapp.kcfinder.freemarker.FreemarkerManager;

import freemarker.template.TemplateException;

public class Dispatcher {

    /**
     * Logger
     */
    private static final Log Logger = LogFactory.getLog(Dispatcher.class);

    /**
     * 提供一个本地线程实例对象
     */
    private static final ThreadLocal<Dispatcher> instance = new ThreadLocal<Dispatcher>();
    
    /**
     * Action映射文件配置默认地址
     */
    private static final String DEFAULT_CONFIGURATION_PATHS = "xxxx.xml";
    
    /**
     * 属性配置文件默认地址
     */
    private static final String DEFAULT_SETTINGS_PATHS = "classpath:/com/demo/webapp/kcfinder/config/default.properties";
    
    /** 
     * Action映射配置文件路径
     **/
    private String configuration = DEFAULT_CONFIGURATION_PATHS;
    
    /**
     * 属性配置文件的自定义文件路径
     */
    private String settings = "/";
    
    /**
     * 属性配置文件
     */
	protected Properties properties;
	
	/**
	 * Servlet上下文
	 */
	protected ServletContext servletContext;
	
	/**
	 * Freemarker管理器
	 */
	protected FreemarkerManager freemarkerManager;
	
	/**
	 * Action配置文件管理器
	 */
	protected ConfigurationManager configurationManager;
	
	/**
	 * 对象工厂,创建Action/Result/Interceptor等对象
	 */
	protected ObjectFactory objectFactory = new ObjectFactory();
	
	/**
	 * ActionMapping生成器
	 */
	private List<ActionMappingBuilder> builders = new ArrayList<ActionMappingBuilder>();
	
    public Dispatcher(ServletContext servletContext) {
        this.servletContext = servletContext;
    }
    
    public static Dispatcher getInstance() {
        return instance.get();
    }

    public static void setInstance(Dispatcher instance) {
        Dispatcher.instance.set(instance);
    }
    
    /**
     * 初始化
     */
    public void init() {
    	
    	//取的初始化配置参数
    	initSettings();
    	
    	//配置映射Builder
    	initActionBuilder();
    	
    	//配置文件初始化
    	initConfiguration();
    	
    	//配置FreemarkerManager
    	initFreemarkerManager();
    }
    
    protected void initSettings() {
    	
    	if (properties == null) {
    		properties = loadSettings(servletContext, settings, DEFAULT_SETTINGS_PATHS);
    	}
    	//取的对象工厂配置
    	String strObjectFactory = this.getSettings(KCFinderStatics.KCFINDER_KEY_OBJECT_FACTORY);
    	try {
    		//创建对象工厂
			this.objectFactory = (ObjectFactory) ClassLoaderUtils.loadClass(strObjectFactory, this.getClass()).newInstance();
			objectFactory.init(servletContext);
		} catch (Exception e) {
			Logger.warn(strObjectFactory + " create fault.", e.getCause());
			this.objectFactory = new ObjectFactory();
		} 
    }
    
    protected void initActionBuilder() {
    	//配置ActionMapping的Builder对象
    	String builderStr = this.getSettings(KCFinderStatics.SERVLET_CONFIGURATION_BUILDER);
		if (StringUtils.isEmpty(builderStr)) {
			builderStr = KCFinderStatics.DEFAULT_ACTIONMAPPING_BUILDER;
		}
		ActionMappingBuilder actionMappingBuilder = null;
		for (String builder : builderStr.split(",")) {
			try {
				//ClassLoader loader = Thread.currentThread().getContextClassLoader();
				//loader = filterConfig.getServletContext().getClass().getClassLoader();
				//actionMappingBuilder = loadClass(builder, loader != null ? loader : getClass().getClassLoader());
				//actionMappingBuilder = (ActionMappingBuilder) Class.forName(builder, true, getClass().getClassLoader()).newInstance();
				actionMappingBuilder = (ActionMappingBuilder) objectFactory.buildBean(builder, new HashMap<String, Object>(), true);
			} catch (Exception e) {
				Logger.error(e.getMessage());
				e.printStackTrace();
			}
			builders.add(actionMappingBuilder);
		}
    }
    
    protected void initConfiguration() {
    	
    	configurationManager = new ConfigurationManager(configuration);
    	configurationManager.load();
    	//configurationManager.getConfiguration();
    }
    
    protected void initFreemarkerManager() {
    	
    	if (freemarkerManager == null) {
    		freemarkerManager = new FreemarkerManager();
    		try {
				freemarkerManager.getConfiguration(servletContext);
			} catch (TemplateException e) {
				throw new ConfigurationException("have a freemarker exception in Dispatcher:initFreemarkerManager.", e.getCause());
			}
    	}
    }
    
    public HttpServletRequest wrapRequest(HttpServletRequest request, ServletContext servletContext) throws IOException {

        if (request instanceof KCFinderRequestWrapper) {
            return request;
        }
//        String content_type = request.getContentType();
//        if (content_type != null && content_type.contains("multipart/form-data")) {
//            MultiPartRequest mpr = null;
//            request = new MultiPartRequestWrapper(mpr, request, getSaveDir(servletContext));
//        } else {
//            request = new KCFinderRequestWrapper(request);
//        }
        return new KCFinderRequestWrapper(request);
    }
    
    public void cleanup() {
    	ActionContext.setContext(null);

        // clean up configuration
    	configurationManager.destroy();
    	configurationManager = null;
    }

	public String executeAction(HttpServletRequest request, HttpServletResponse response, ServletContext context, ActionMapping mapping) {
		
		//ActionContext ctx = ActionContext.getContext();
		//ctx.setRequest(request);
		//ctx.setResponse(response);
		
		Map<String, Object> extendtionsMap = createExtensionMap(request, response, context, mapping);
		
		Configuration configuration = this.getConfigurationManager().getConfiguration();
		PackageConfig packageConfig = configuration.getPackageConfig(mapping.getNamespace());
		ActionConfig actionConfig = packageConfig.getConfig(mapping.getName(), mapping.getMethod());
		ActionProxy proxy = proxyBuilder(packageConfig, actionConfig, mapping, extendtionsMap);
		
		String result = "";
		
		try {
			result = proxy.execute();
		} catch (Exception e) {
			e.printStackTrace();
			Logger.error(e.getMessage());
			sendError();
			return null;
		}
		
		return result;
	}
	
	protected ActionProxy proxyBuilder(PackageConfig packageConfig, ActionConfig actionConfig, ActionMapping mapping, Map<String, Object> extendtionsMap) {
		//创建一个Action执行代理
		ActionProxy proxy = new DefaultActionProxy(packageConfig, actionConfig, mapping, extendtionsMap, this.objectFactory);
		return proxy;
	}
	
	private Map<String, Object> createExtensionMap(HttpServletRequest request, HttpServletResponse response, ServletContext context, ActionMapping mapping) {
		Map<String, Object> extensionMap = new HashMap<String, Object>();
		
		extensionMap.put(KCFinderStatics.HTTP_SERVLET_REQUEST, request);
		extensionMap.put(KCFinderStatics.HTTP_SERVLET_RESPONSE, response);
		extensionMap.put(KCFinderStatics.HTTP_SERVLET_CONTEXT, context);
		//extensionMap.put(KCFinderStatics.HTTP_SERVLET_RESPONSE, mapping);
		return extensionMap;
	}
	
	protected void sendError() {
		
	}
	
	protected synchronized Properties loadSettings(ServletContext servletContext, String settings, String defaultPath) {

		// 使用自定义配置
		//String settings = servletContext.getInitParameter(initKey);
		InputStream in = null;
		if (StringUtils.isEmpty(settings)) {
			in = servletContext.getResourceAsStream(settings);
		}
		Properties properties = new Properties();
		// 如果无法得到用户配置信息,则使用默认配置信息
		if (in == null) {
			try {
				in = ClassLoaderUtils.getResourceAsStream(defaultPath, this.getClass());
				properties.load(in);
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return properties;
	}
	
	public List<ActionMappingBuilder> getBuilders() {
		return builders;
	}
	

	public void setConfigurationPath(String configuration) {
		this.configuration = configuration;
	}
	
	public String getConfigurationPath() {
		return configuration;
	}
	
	public Properties getProperties() {
		return properties;
	}

	public void setProperties(Properties properties) {
		this.properties = properties;
	}

	public String getSettings(String key) {
		return (String) properties.get(key);
	}
	
	public void setSettings(String key, String value) {
		properties.setProperty(key, value);
	}

	public FreemarkerManager getFreemarkerManager() {
		return freemarkerManager;
	}

	public void setFreemarkerManager(FreemarkerManager freemarkerManager) {
		this.freemarkerManager = freemarkerManager;
	}

	public void setConfigurationManager(ConfigurationManager configurationManager) {
		this.configurationManager = configurationManager;
	}

	public ConfigurationManager getConfigurationManager() {
		return configurationManager;
	}

	public void setObjectFactory(ObjectFactory objectFactory) {
		this.objectFactory = objectFactory;
	}

	public ObjectFactory getObjectFactory() {
		return objectFactory;
	}

	public void setPropertiesPath(String settings) {
		this.settings = settings;
	}
}
